﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using dotUML.System;

namespace dotUML.Core.Common
{
    /// <summary>
    /// Model class implements the IModel interface. This class
    /// is only accessible within dotUML.Core.Common namespace. It provides
    /// an access point to model elements.
    /// </summary>
    class Model : IModel
    {
        Dictionary<string, IStereotype> _stereotypes;
        List<IDiagram> _diagrams;
        Dictionary<string, ISequenceDiagram> _sequenceDiagramStructure;
        Dictionary<string, IComponentDiagram> _componentDiagramStructure;

        /// <summary>
        /// UML stereotypes.
        /// </summary>
        public Dictionary<string, IStereotype> Stereotypes
        {
            get { return _stereotypes; }
            set { _stereotypes = value; }
        }
        /// <summary>
        /// UML diagrams contained in the model.
        /// </summary>
        public List<IDiagram> Diagrams
        {
            get { return _diagrams; }
            set { _diagrams = value; }
        }
        /// <summary>
        /// Sequence diagrams contained in the model.
        /// </summary>
        public Dictionary<string, ISequenceDiagram> SequenceDiagramStructure
        {
            get { return _sequenceDiagramStructure; }
            set { _sequenceDiagramStructure = value; }
        }
        /// <summary>
        /// Component diagrams contained in the model.
        /// </summary>
        public Dictionary<string, IComponentDiagram> ComponentDiagramStructure
        {
            get { return _componentDiagramStructure; }
            set { _componentDiagramStructure = value; }
        }


        /// <summary>
        /// Class constructor.
        /// </summary>
        public Model()
        {
            Errors = new List<IError>();
            Stereotypes = new Dictionary<string, IStereotype>();
            Diagrams = new List<IDiagram>();
            SequenceDiagramStructure = new Dictionary<string, ISequenceDiagram>();
            ComponentDiagramStructure = new Dictionary<string, IComponentDiagram>();
        }

        #region IModel Members

        List<IError> _errors;

        /// <summary>
        /// List of validation errors.
        /// </summary>
        public List<IError> Errors
        {
            get
            {
                return _errors;
            }
            set
            {
                _errors = value;
            }
        }

        /// <summary>
        /// Create a stereotype and add it to the model.
        /// Throws an error if a stereotype with the provided name already exists.
        /// </summary>
        /// <param name="Name">Stereotype name.</param>
        /// <returns>Newly created stereotype.</returns>
        public IStereotype AddStereotype(string Name)
        {
            if (Stereotypes.ContainsKey(Name))
            {
                throw new CommonException(string.Format(Resources.Model_AddStereotype_AlreadyExists, Name));
            }

            IStereotype result = (IStereotype)InstrumentationManager.InstrumentObject(new Stereotype(Name), EInstrumentationType.Logging);
            Stereotypes.Add(Name, result);

            return result;
        }

        /// <summary>
        /// Get a stereotype.
        /// </summary>
        /// <param name="Name">Stereotype name.</param>
        /// <returns>Required stereotype or null, if it does not exist.</returns>
        public IStereotype GetStereotype(string Name)
        {
            IStereotype result = null;

            if (Stereotypes.ContainsKey(Name))
            {
                result = Stereotypes[Name];
            }

            return result;
        }

        /// <summary>
        /// Delete a stereotype. If required stereotype does not exist, does nothing.
        /// </summary>
        /// <param name="Name">Stereotype name.</param>
        public void DeleteStereotype(string Name)
        {
            if (Stereotypes.ContainsKey(Name))
            {
                Stereotypes.Remove(Name);
            }
        }
        
        /// <summary>
        /// Collection of stereotypes names.
        /// </summary>
        public ICollection<string> StereotypeNames
        {
            get
            {
                return Stereotypes.Keys;
            }
        }



        /// <summary>
        /// Create a sequence diagram and add it to the model.
        /// Throws an error if a sequence diagram with the provided name already exists.
        /// </summary>
        /// <param name="Name">Sequence diagram name.</param>
        /// <returns>Newly created sequence diagram.</returns>
        public ISequenceDiagram AddSequenceDiagram(string Name)
        {
            ICollection<string> str = SequenceDiagramStructure.Keys;

            if (SequenceDiagramStructure.ContainsKey(Name))
            {
                throw new CommonException(string.Format(Resources.Model_AddSequenceDiagram_AlreadyExists, Name));
            }

            ISequenceDiagram result = (ISequenceDiagram)InstrumentationManager.InstrumentObject(new SequenceDiagram.SequenceDiagram(), EInstrumentationType.Logging);
            result.Name = Name;
            result.DiagramType = EDiagramType.Sequence;
            SequenceDiagramStructure.Add(Name, result);

            return result;
        }

        /// <summary>
        /// Get a sequence diagram.
        /// </summary>
        /// <param name="Name">Sequence diagram name.</param>
        /// <returns>Required sequence diagram or null, if it does not exist.</returns>
        public ISequenceDiagram GetSequenceDiagram(string Name)
        {
            ISequenceDiagram result = null;

            if (SequenceDiagramStructure.ContainsKey(Name))
            {
                result = SequenceDiagramStructure[Name];
            }

            return result;
        }

        /// <summary>
        /// Delete a sequence diagram. If required sequence diagram does not exist, does nothing.
        /// </summary>
        /// <param name="Name">Sequence diagram name.</param>
        public void DeleteSequenceDiagram(string Name)
        {
            if (SequenceDiagramStructure.ContainsKey(Name))
            {
                SequenceDiagramStructure.Remove(Name);
            }
        }

        /// <summary>
        /// Collection of sequence diagrams names.
        /// </summary>
        public ICollection<string> SequenceDiagramNames
        {
            get
            {
                return SequenceDiagramStructure.Keys;
            }
        }


        /// <summary>
        /// Create a component diagram and add it to the model.
        /// Throws an error if a component diagram with the provided name already exists.
        /// </summary>
        /// <param name="Name">Component diagram name.</param>
        /// <returns>Newly created component diagram.</returns>
        public IComponentDiagram AddComponentDiagram(string Name)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Get a component diagram.
        /// </summary>
        /// <param name="Name">Component diagram name.</param>
        /// <returns>Required component diagram or null, if it does not exist.</returns>
        public IComponentDiagram GetComponentDiagram(string Name)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Delete a component diagram. If required component diagram does not exist, does nothing.
        /// </summary>
        /// <param name="Name">Component diagram name.</param>
        public void DeleteComponentDiagram(string Name)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Collection of component diagrams names.
        /// </summary>
        public ICollection<string> ComponentDiagramNames
        {
            get
            {
                throw new NotImplementedException();
            }
        }

        /// <summary>
        /// Validate the correctness of the model.
        /// Puts the validation errors to the Errors field.
        /// </summary>
        /// <returns>True if the validation is successful, otherwise false.</returns>
        public bool Validate()
        {
            throw new NotImplementedException();
        }

        #endregion

        /// <summary>
        /// Create new model error.
        /// </summary>
        /// <param name="ErrorType">Error type.</param>
        /// <param name="Message">Error message.</param>
        public void NewError(EErrorType ErrorType, string Message)
        {
            Errors.Add(ErrorFactory.NewError(ErrorType, Message));
        }

    }
}
